#ifndef _TVM_INSTRUCTION_H_
#define _TVM_INSTRUCTION_H_

#define INST_GROUP_SPECIAL			0x0	/*the group for those special instructions*/
#define INST_GROUP_MOV					0x1	/*the group for move instructions*/
#define INST_GROUP_CMP					0x2	/*the group for compare instructions*/
#define INST_GROUP_WAIT					0x3	/*the group for wait instructions*/
#define INST_GROUP_OFFSET			0x5	/*the offset of the group bits in the instruction byte*/			


/*definitions for register selection*/
#define REG_SEL_AX					0x0
#define REG_SEL_BX					0x1
#define REG_SEL_CX					0x2
#define REG_SEL_DX					0x3
#define REG_SEL_OFFSET		0x3


/*definitions for operand size indicator*/
#define SIZE_IND_NONE					0x0/*no operand*/
#define SIZE_IND_BYTE					0x1/*1 byte indicator*/
#define SIZE_IND_WORD					0x2
#define SIZE_IND_THREE_BYTE		0x3
#define SIZE_IND_DWORD				0x4
#define SIZE_IND_OFFSET				0x0


/*definitions for the sub-group of those special instructions*/
#define SPCL_INST_NO_OPERAND		0x0
#define SPCL_INST_JUMP							0x1
#define SPCL_INST_SEND						0x2
#define SPCL_INST_SLEEP						0x3
#define SPCL_INST_OFFSET					REG_SEL_OFFSET


/*definitions for those special instructions which have no operand*/
#define NO_OP_INST_LOG				0x0
#define NO_OP_INST_INC_CX			0x1
#define NO_OP_INST_DEC_CX		0x2
#define NO_OP_INST_PAUSE			0x3
#define NO_OP_INST_HALT 				0x4


#define JUMP_EQUAL						0x0
#define JUMP_NOT_EQUAL			0x1
#define JUMP_BELOW					0x2
#define JUMP_BELOW_EQUAL	0x3
#define JUMP_ABOVE					0x4
#define JUMP_ABOVE_EQUAL		0x5
#define JUMP_JMP							0x6


/*definitions for event slot. there are 32 of them*/
#define EVENT_SLOT_1			0
#define EVENT_SLOT_2			1
#define EVENT_SLOT_3			2
#define EVENT_SLOT_4			3
#define EVENT_SLOT_5			4
#define EVENT_SLOT_6			5
#define EVENT_SLOT_7			6
#define EVENT_SLOT_8			7
#define EVENT_SLOT_9			8
#define EVENT_SLOT_10		9
#define EVENT_SLOT_11		10
#define EVENT_SLOT_12		11
#define EVENT_SLOT_13		12
#define EVENT_SLOT_14		13
#define EVENT_SLOT_15		14
#define EVENT_SLOT_16		15
#define EVENT_SLOT_17		16
#define EVENT_SLOT_18		17
#define EVENT_SLOT_19		18
#define EVENT_SLOT_20		19
#define EVENT_SLOT_21		20
#define EVENT_SLOT_22		21
#define EVENT_SLOT_23		22
#define EVENT_SLOT_24		23
#define EVENT_SLOT_25		24
#define EVENT_SLOT_26		25
#define EVENT_SLOT_27		26
#define EVENT_SLOT_28		27
#define EVENT_SLOT_29		28
#define EVENT_SLOT_30		29
#define EVENT_SLOT_31		30
#define EVENT_SLOT_32		31
#define EVENT_SLOT_MIN		EVENT_SLOT_1
#define EVENT_SLOT_MAX		EVENT_SLOT_32


/*instructions definitions*/
/*special group*/
/*no operand sub group
actually, log instruction do have operand, but it's self defined, so no
need to specify the operand*/
#define INST_LOG				(INST_GROUP_SPECIAL << INST_GROUP_OFFSET) + \
												(SPCL_INST_NO_OPERAND << SPCL_INST_OFFSET) + NO_OP_INST_LOG
#define INST_INC_CX			(INST_GROUP_SPECIAL << INST_GROUP_OFFSET) + \
												(SPCL_INST_NO_OPERAND << SPCL_INST_OFFSET) + NO_OP_INST_INC_CX
#define INST_DEC_CX		(INST_GROUP_SPECIAL << INST_GROUP_OFFSET) + \
												(SPCL_INST_NO_OPERAND << SPCL_INST_OFFSET) + NO_OP_INST_DEC_CX
#define INST_PAUSE			(INST_GROUP_SPECIAL << INST_GROUP_OFFSET) + \
												(SPCL_INST_NO_OPERAND << SPCL_INST_OFFSET) + NO_OP_INST_PAUSE
#define INST_HALT				(INST_GROUP_SPECIAL << INST_GROUP_OFFSET) + \
												(SPCL_INST_NO_OPERAND << SPCL_INST_OFFSET) +NO_OP_INST_HALT
/*jump sub group*/
#define INST_JUMP_EQUAL				  		(INST_GROUP_SPECIAL << INST_GROUP_OFFSET) + \
																		(SPCL_INST_JUMP << SPCL_INST_OFFSET) + JUMP_EQUAL
#define INST_JUMP_NOT_EQUAL			(INST_GROUP_SPECIAL << INST_GROUP_OFFSET) + \
																		(SPCL_INST_JUMP << SPCL_INST_OFFSET) + JUMP_NOT_EQUAL
#define INST_JUMP_BELOW				  		(INST_GROUP_SPECIAL << INST_GROUP_OFFSET) + \
																		(SPCL_INST_JUMP << SPCL_INST_OFFSET) + JUMP_BELOW
#define INST_JUMP_BELOW_EQUAL		(INST_GROUP_SPECIAL << INST_GROUP_OFFSET) + \
																		(SPCL_INST_JUMP << SPCL_INST_OFFSET) + JUMP_BELOW_EQUAL
#define INST_JUMP_ABOVE				  		(INST_GROUP_SPECIAL << INST_GROUP_OFFSET) + \
																		(SPCL_INST_JUMP << SPCL_INST_OFFSET) + JUMP_ABOVE
#define INST_JUMP_ABOVE_EQUAL	  	(INST_GROUP_SPECIAL << INST_GROUP_OFFSET) + \
																		(SPCL_INST_JUMP << SPCL_INST_OFFSET) + JUMP_ABOVE_EQUAL
/*send sub group. cause we only need to send remote key, which should below UINT8_MAX, so only
need one instruction. but we preserved the 3bit in case of extension is needed in future*/
#define INST_SEND_1		(INST_GROUP_SPECIAL << INST_GROUP_OFFSET) + (SPCL_INST_SEND << SPCL_INST_OFFSET) + SIZE_IND_BYTE
/*sleep sub group*/
#define INST_SLEEP_1		(INST_GROUP_SPECIAL << INST_GROUP_OFFSET) + \
												(SPCL_INST_SLEEP << SPCL_INST_OFFSET) + SIZE_IND_BYTE
#define INST_SLEEP_2		(INST_GROUP_SPECIAL << INST_GROUP_OFFSET) + \
												(SPCL_INST_SLEEP << SPCL_INST_OFFSET) + SIZE_IND_WORD
#define INST_SLEEP_3		(INST_GROUP_SPECIAL << INST_GROUP_OFFSET) + \
												(SPCL_INST_SLEEP << SPCL_INST_OFFSET) + SIZE_IND_THREE_BYTE
#define INST_SLEEP_4		(INST_GROUP_SPECIAL << INST_GROUP_OFFSET) + \
												(SPCL_INST_SLEEP << SPCL_INST_OFFSET) + SIZE_IND_DWORD

/*move group*/
/*move AX*/
#define INST_MOVE_AX_1			(INST_GROUP_MOV << INST_GROUP_OFFSET) + \
															(REG_SEL_AX << REG_SEL_OFFSET) + SIZE_IND_BYTE
#define INST_MOVE_AX_2			(INST_GROUP_MOV << INST_GROUP_OFFSET) + \
															(REG_SEL_AX << REG_SEL_OFFSET) + SIZE_IND_WORD
#define INST_MOVE_AX_3			(INST_GROUP_MOV << INST_GROUP_OFFSET) + \
															(REG_SEL_AX << REG_SEL_OFFSET) + SIZE_IND_THREE_BYTE
#define INST_MOVE_AX_4			(INST_GROUP_MOV << INST_GROUP_OFFSET) + \
															(REG_SEL_AX << REG_SEL_OFFSET) + SIZE_IND_DWORD
/*move BX*/
#define INST_MOVE_BX_1			(INST_GROUP_MOV << INST_GROUP_OFFSET) + \
															(REG_SEL_BX << REG_SEL_OFFSET) + SIZE_IND_BYTE
#define INST_MOVE_BX_2			(INST_GROUP_MOV << INST_GROUP_OFFSET) + \
															(REG_SEL_BX << REG_SEL_OFFSET) + SIZE_IND_WORD
#define INST_MOVE_BX_3			(INST_GROUP_MOV << INST_GROUP_OFFSET) + \
															(REG_SEL_BX << REG_SEL_OFFSET) + SIZE_IND_THREE_BYTE
#define INST_MOVE_BX_4			(INST_GROUP_MOV << INST_GROUP_OFFSET) + \
															(REG_SEL_BX << REG_SEL_OFFSET) + SIZE_IND_DWORD
/*move CX*/
#define INST_MOVE_CX_1			(INST_GROUP_MOV << INST_GROUP_OFFSET) + \
															(REG_SEL_CX << REG_SEL_OFFSET) + SIZE_IND_BYTE
#define INST_MOVE_CX_2			(INST_GROUP_MOV << INST_GROUP_OFFSET) + \
															(REG_SEL_CX << REG_SEL_OFFSET) + SIZE_IND_WORD
#define INST_MOVE_CX_3			(INST_GROUP_MOV << INST_GROUP_OFFSET) + \
															(REG_SEL_CX << REG_SEL_OFFSET) + SIZE_IND_THREE_BYTE
#define INST_MOVE_CX_4			(INST_GROUP_MOV << INST_GROUP_OFFSET) + \
															(REG_SEL_CX << REG_SEL_OFFSET) + SIZE_IND_DWORD
/*move DX*/
#define INST_MOVE_DX_1			(INST_GROUP_MOV << INST_GROUP_OFFSET) + \
															(REG_SEL_DX << REG_SEL_OFFSET) + SIZE_IND_BYTE
#define INST_MOVE_DX_2			(INST_GROUP_MOV << INST_GROUP_OFFSET) + \
															(REG_SEL_DX << REG_SEL_OFFSET) + SIZE_IND_WORD
#define INST_MOVE_DX_3			(INST_GROUP_MOV << INST_GROUP_OFFSET) + \
															(REG_SEL_DX << REG_SEL_OFFSET) + SIZE_IND_THREE_BYTE
#define INST_MOVE_DX_4			(INST_GROUP_MOV << INST_GROUP_OFFSET) + \
															(REG_SEL_DX << REG_SEL_OFFSET) + SIZE_IND_DWORD

/*compare group*/
/*compare AX*/
#define INST_CMP_AX					(INST_GROUP_CMP << INST_GROUP_OFFSET) + \
															(REG_SEL_AX << REG_SEL_OFFSET) + SIZE_IND_NONE
#define INST_CMP_AX_1				(INST_GROUP_CMP << INST_GROUP_OFFSET) + \
															(REG_SEL_AX << REG_SEL_OFFSET) + SIZE_IND_BYTE
#define INST_CMP_AX_2				(INST_GROUP_CMP << INST_GROUP_OFFSET) + \
															(REG_SEL_AX << REG_SEL_OFFSET) + SIZE_IND_WORD
#define INST_CMP_AX_3				(INST_GROUP_CMP << INST_GROUP_OFFSET) + \
															(REG_SEL_AX << REG_SEL_OFFSET) + SIZE_IND_THREE_BYTE
#define INST_CMP_AX_4				(INST_GROUP_CMP << INST_GROUP_OFFSET) + \
															(REG_SEL_AX << REG_SEL_OFFSET) + SIZE_IND_DWORD
/*compare BX*/
#define INST_CMP_BX					(INST_GROUP_CMP << INST_GROUP_OFFSET) + \
															(REG_SEL_BX << REG_SEL_OFFSET) + SIZE_IND_NONE
#define INST_CMP_BX_1				(INST_GROUP_CMP << INST_GROUP_OFFSET) + \
															(REG_SEL_BX << REG_SEL_OFFSET) + SIZE_IND_BYTE
#define INST_CMP_BX_2				(INST_GROUP_CMP << INST_GROUP_OFFSET) + \
															(REG_SEL_BX << REG_SEL_OFFSET) + SIZE_IND_WORD
#define INST_CMP_BX_3				(INST_GROUP_CMP << INST_GROUP_OFFSET) + \
															(REG_SEL_BX << REG_SEL_OFFSET) + SIZE_IND_THREE_BYTE
#define INST_CMP_BX_4				(INST_GROUP_CMP << INST_GROUP_OFFSET) + \
															(REG_SEL_BX << REG_SEL_OFFSET) + SIZE_IND_DWORD
/*compare CX*/
#define INST_CMP_CX					(INST_GROUP_CMP << INST_GROUP_OFFSET) + \
															(REG_SEL_CX << REG_SEL_OFFSET) + SIZE_IND_NONE
#define INST_CMP_CX_1				(INST_GROUP_CMP << INST_GROUP_OFFSET) + \
															(REG_SEL_CX << REG_SEL_OFFSET) + SIZE_IND_BYTE
#define INST_CMP_CX_2				(INST_GROUP_CMP << INST_GROUP_OFFSET) + \
															(REG_SEL_CX << REG_SEL_OFFSET) + SIZE_IND_WORD
#define INST_CMP_CX_3		 		(INST_GROUP_CMP << INST_GROUP_OFFSET) + \
															(REG_SEL_CX << REG_SEL_OFFSET) + SIZE_IND_THREE_BYTE
#define INST_CMP_CX_4				(INST_GROUP_CMP << INST_GROUP_OFFSET) + \
															(REG_SEL_CX << REG_SEL_OFFSET) + SIZE_IND_DWORD
/*compare DX*/
#define INST_CMP_DX					(INST_GROUP_CMP << INST_GROUP_OFFSET) + \
															(REG_SEL_DX << REG_SEL_OFFSET) + SIZE_IND_NONE
#define INST_CMP_DX_1				(INST_GROUP_CMP << INST_GROUP_OFFSET) + \
															(REG_SEL_DX << REG_SEL_OFFSET) + SIZE_IND_BYTE
#define INST_CMP_DX_2		 		(INST_GROUP_CMP << INST_GROUP_OFFSET) + \
															(REG_SEL_DX << REG_SEL_OFFSET) + SIZE_IND_WORD
#define INST_CMP_DX_3				(INST_GROUP_CMP << INST_GROUP_OFFSET) + \
															(REG_SEL_DX << REG_SEL_OFFSET) + SIZE_IND_THREE_BYTE
#define INST_CMP_DX_4				(INST_GROUP_CMP << INST_GROUP_OFFSET) + \
															(REG_SEL_DX << REG_SEL_OFFSET) + SIZE_IND_DWORD

/*wait group: instructions for wait operations*/
#define INST_WAIT_FOR_SLOT_1  	(INST_GROUP_WAIT << INST_GROUP_OFFSET) + \
																	EVENT_SLOT_1
#define INST_WAIT_FOR_SLOT_2  	(INST_GROUP_WAIT << INST_GROUP_OFFSET) + \
																	EVENT_SLOT_2
#define INST_WAIT_FOR_SLOT_3  	(INST_GROUP_WAIT << INST_GROUP_OFFSET)  + \
																	EVENT_SLOT_3
#define INST_WAIT_FOR_SLOT_4  	(INST_GROUP_WAIT << INST_GROUP_OFFSET)  + \
																	EVENT_SLOT_4
#define INST_WAIT_FOR_SLOT_5  	(INST_GROUP_WAIT << INST_GROUP_OFFSET)  + \
																	EVENT_SLOT_5
#define INST_WAIT_FOR_SLOT_6  	(INST_GROUP_WAIT << INST_GROUP_OFFSET)  + \
																	EVENT_SLOT_6
#define INST_WAIT_FOR_SLOT_7  	(INST_GROUP_WAIT << INST_GROUP_OFFSET)  + \
																	EVENT_SLOT_7
#define INST_WAIT_FOR_SLOT_8  	(INST_GROUP_WAIT << INST_GROUP_OFFSET) + \
																	EVENT_SLOT_8
#define INST_WAIT_FOR_SLOT_9  	(INST_GROUP_WAIT << INST_GROUP_OFFSET) + \
																	EVENT_SLOT_9
#define INST_WAIT_FOR_SLOT_10  	(INST_GROUP_WAIT << INST_GROUP_OFFSET) + \
																	EVENT_SLOT_10
#define INST_WAIT_FOR_SLOT_11  	(INST_GROUP_WAIT << INST_GROUP_OFFSET) + \
																	EVENT_SLOT_11
#define INST_WAIT_FOR_SLOT_12  	(INST_GROUP_WAIT << INST_GROUP_OFFSET) + \
																	EVENT_SLOT_12
#define INST_WAIT_FOR_SLOT_13  	(INST_GROUP_WAIT << INST_GROUP_OFFSET) + \
																	EVENT_SLOT_13
#define INST_WAIT_FOR_SLOT_14  	(INST_GROUP_WAIT << INST_GROUP_OFFSET) + \
																	EVENT_SLOT_14
#define INST_WAIT_FOR_SLOT_15  	(INST_GROUP_WAIT << INST_GROUP_OFFSET) + \
																	EVENT_SLOT_15
#define INST_WAIT_FOR_SLOT_16  	(INST_GROUP_WAIT << INST_GROUP_OFFSET) + \
																	EVENT_SLOT_16
#define INST_WAIT_FOR_SLOT_17  	(INST_GROUP_WAIT << INST_GROUP_OFFSET) + \
																	EVENT_SLOT_17
#define INST_WAIT_FOR_SLOT_18  	(INST_GROUP_WAIT << INST_GROUP_OFFSET) + \
																	EVENT_SLOT_18
#define INST_WAIT_FOR_SLOT_19  	(INST_GROUP_WAIT << INST_GROUP_OFFSET) + \
																	EVENT_SLOT_19
#define INST_WAIT_FOR_SLOT_20  	(INST_GROUP_WAIT << INST_GROUP_OFFSET) + \
																	EVENT_SLOT_20
#define INST_WAIT_FOR_SLOT_21  	(INST_GROUP_WAIT << INST_GROUP_OFFSET) + \
																	EVENT_SLOT_21
#define INST_WAIT_FOR_SLOT_22  	(INST_GROUP_WAIT << INST_GROUP_OFFSET) + \
																	EVENT_SLOT_22
#define INST_WAIT_FOR_SLOT_23  	(INST_GROUP_WAIT << INST_GROUP_OFFSET) + \
																	EVENT_SLOT_23
#define INST_WAIT_FOR_SLOT_24 	(INST_GROUP_WAIT << INST_GROUP_OFFSET) + \
																	EVENT_SLOT_24
#define INST_WAIT_FOR_SLOT_25  	(INST_GROUP_WAIT << INST_GROUP_OFFSET) + \
																	EVENT_SLOT_25
#define INST_WAIT_FOR_SLOT_26  	(INST_GROUP_WAIT << INST_GROUP_OFFSET) + \
																	EVENT_SLOT_26
#define INST_WAIT_FOR_SLOT_27  	(INST_GROUP_WAIT << INST_GROUP_OFFSET) + \
																	EVENT_SLOT_27
#define INST_WAIT_FOR_SLOT_28  	(INST_GROUP_WAIT << INST_GROUP_OFFSET) + \
																	EVENT_SLOT_28
#define INST_WAIT_FOR_SLOT_29  	(INST_GROUP_WAIT << INST_GROUP_OFFSET) + \
																	EVENT_SLOT_29
#define INST_WAIT_FOR_SLOT_30  	(INST_GROUP_WAIT << INST_GROUP_OFFSET) + \
																	EVENT_SLOT_30
#define INST_WAIT_FOR_SLOT_31  	(INST_GROUP_WAIT << INST_GROUP_OFFSET) + \
																	EVENT_SLOT_31
#define INST_WAIT_FOR_SLOT_32  	(INST_GROUP_WAIT << INST_GROUP_OFFSET) + 	EVENT_SLOT_32


#endif/*_TVM_INSTRUCTION_H_*/
